<?php

/**
* SOURDOUGH Shared Library
* Directory structure listing class
*
* aFiles contains multiple aFile entries
* aFile:   Path        => relative path eg. ../xx/yy/
*          File        => filename eg. filename (without extension)
*          Extension   => ext
*          IsDirectory => true/false
*          FullName    => Path . File . "." . Extension
*          FileName    => File . "." . Extension
*
* Notes
* Filenames with multiple Extensions: only the last extensions is saved as extensions
* eg: aaa.bbb.ccc results in File=aaa.bbb and Extension=ccc
* Filenames are stored in the same case as the are stored in the filesystem
* sFilter is only applied to files.
*
*
* @package      sourdough
* @subpackage   dir
* @author       Philip Iezzi <pipo@phpee.com>
* @copyright    Copyright (c)2000-2006 PHPEE.COM
* @copyright    based on CDir class by Hannes Dorn <hannes@dorn.cc> (28.11.2000), phpclasses.org
* @license      http://opensource.org/licenses/lgpl-license.php GNU Lesser General Public License
* @version      $Id: DirScan.php 101 2010-03-20 01:35:29Z hami $
*/
class Sfs_Filesystem_DirScan {
//[start] Constants
	/**
	 * include regular expression: web image extensions
	 */
	const REGEX_INCL_WEBIMAGES = "(jpg|jpeg|gif|png)\$";
	/**
	 * exclude regular expression: default file/directory exclusion
	 */
	const REGEX_EXCL_DEFAULT = "(_vti_)|(vssver.scc)|(CVS)|(.htaccess)|(.htpasswd)|(.svn)";
//[end]

//[start] Local Variables

	/**
	* Array of scanned files
	*
	* @var      array        $aFiles
	*/
	public $aFiles;

	/**
	* 當有例外目錄時,是否繼續往子目錄搜查
	* @var 	boolean 	$isRecursive
	*/
	public $isRecursiveDir = true;
//[end]

//[start] Constructor
	/**
	* Sd_DirScan constructor
	*
	* @return   void
	*/
	public function __construct()
	{

		$this->init();
	}
//[end]

//[start] Public Methods
	/**
	* Initialization
	*
	* @return   void
	*/
	public function init()
	{
		unset( $this->aFiles );
		$this->aFiles = array();
	}
	/**
	* Scan directory structure
	*
	* @param    string      $sPath        path eg. "../xx/yy/" (note the last "/")
	* @param    string      $sInclude     regular expression for filtering path- and filenames
	* @param    boolean     $fRecursive   true/false: go down the whole structure
	* @param    boolean     $fFiles       result set will contain entries which are files
	* @param    boolean     $fDirectory   result set will contain entries which are directories
	* @param    string      $sRoot        Root-Path. Will be appended to the entries.
	* @param    string      $sExclude     regular expression for filtering path- and filenames
	* @return   void
	*/
	public function scan($sPath,
	                     $sInclude = "",
	                     $fRecursive = false,
	                     $fFiles = true,
	                     $fDirectories = true,
	                     $sRoot = "",
	                     $sExclude = self::REGEX_EXCL_DEFAULT )
	{
		$oHandle = opendir( $sPath );

		while ( $sFilename = readdir( $oHandle ) ) {
			$fInsert = true;

			if ( $sFilename == "." || $sFilename == ".." )
				continue;

			$fIsDirectory = is_dir( $sPath . $sFilename );

			if ( !$fFiles && !$fIsDirectory )
				$fInsert = false;
			if ( !$fDirectories && $fIsDirectory )
				$fInsert = false;

			// filter files
			if ( $fInsert && !$fIsDirectory && ( !empty( $sInclude ) || !empty( $sExclude ) ) ) {
				$sFullname = $sRoot;
				$sFullname .= $sFilename;

				switch($sInclude) {
					case self::REGEX_INCL_WEBIMAGES:
						$IncEreg = 'eregi'; // case-insensitive
						break;
					default:
						$IncEreg = 'ereg';  // case-sensitive
				}

				if ( !empty( $sInclude ) )
					if ( !$IncEreg( $sInclude, $sFullname ) )
						$fInsert = false;

				if ( !empty( $sExclude ) )
					if ( ereg( $sExclude, $sFullname ) )
						$fInsert = false;
			}

			// filter directories
			if ( $fInsert && $fIsDirectory && !empty( $sExclude ) ) {
				if ( !empty( $sExclude ) )
					if ( ereg( $sExclude, $sFilename ) )
						$fInsert = false;
			}

			if ( $fInsert ) {
				$i = strrpos( $sFilename, "." ) + 1;
				if ( substr( $sFilename, $i - 1, 1 ) == "." ) {
					$sFile = substr( $sFilename, 0, $i - 1 );
					$sExtension = substr( $sFilename, $i );
				} else {
					$sFile = $sFilename;
					$sExtension = "";
				}

				$aFile = array (
					"Path" => $sRoot,
					"File" => $sFile,
					"Extension" => $sExtension,
					"IsDirectory" => $fIsDirectory
					);

				//Insert current file into aFiles array
				$this->aFiles[] = $aFile;
			}

			//Recursion?
			if ( ($this->isRecursiveDir | $fInsert) && $fRecursive && $fIsDirectory )
				$this->scan( $sPath . $sFilename . "/", $sInclude, $fRecursive, $fFiles, $fDirectories, $sRoot . $sFilename . "/", $sExclude );
		}

		closedir( $oHandle );
	}
	/**
	* Count all files/directories
	*
	* @return   integer                   total number of files/directories
	*/
	public function countAll()
	{
		return(count($this->aFiles));
	}
	/**
	* Get all files/directories
	*
	* @param    boolean   $endingSlash    add an ending slash for directories
	* @return   array                     array of files/directories (full path)
	*/
	public function getFileArray( $endingSlash = true )
	{
		$aFullname = array();
		while( list( $sKey, $aFile ) = each( $this->aFiles ) ) {
		    $aFullname[] = $this->FullName( $aFile, $endingSlash );
		}
		return $aFullname;
	}
	/**
	* Output all scanned information to screen
	*
	* @see      OutputFile()
	*/
	public function Output()
	{
		reset( $this->aFiles );
		while( list( $sKey, $aFile ) = each( $this->aFiles ) )
			$this->OutputFile( $aFile );
	}
	/**
	* Output a file/directory's information to screen
	*
	* @see      Output()
	*/
	public function OutputFile( $aFile )
	{
		printf( "Path: %s<br>\n", $this->getPath( $aFile ) );
		printf( "File: %s<br>\n", $this->getFile( $aFile ) );
		printf( "Extension: %s<br>\n", $this->getExtension( $aFile ) );
		printf( "IsDirectory: %s<br>\n", $this->getIsDirectory( $aFile ) ? "true" : "false" );
		printf( "IsFile: %s<br>\n", $this->getIsFile( $aFile ) ? "true" : "false" );
		printf( "FullName: %s<br>\n", $this->FullName( $aFile ) );
		printf( "FileName: %s<br>\n", $this->FileName( $aFile ) );
		printf( "DirectoryName: %s<br>\n", $this->directoryName( $aFile ) );
		echo "<hr>\n";
	}
	/**
	* Get path of a file/directory
	*
	* @param    array     $aFile       file/directory information array
	*/
	public function getPath( $aFile )
	{
		return( $aFile[ "Path" ] );
	}
	/**
	* Get a file's name
	*
	* @param    array     $aFile       file/directory information array
	*/
	public function getFile( $aFile )
	{
		return( $aFile[ "File" ] );
	}
	/**
	* Get a file's extension
	*
	* @param    array     $aFile       file/directory information array
	*/
	public function getExtension( $aFile )
	{
		return( $aFile[ "Extension" ] );
	}
	/**
	* Check if object is a directory
	*
	* @param    array     $aFile       file/directory information array
	*/
	public function getIsDirectory( $aFile )
	{
		return( $aFile[ "IsDirectory" ] );
	}
	/**
	* Check if object is a file
	*
	* @param    array     $aFile       file/directory information array
	*/
	public function getIsFile( $aFile )
	{
		return( !$this->getIsDirectory( $aFile ) );
	}
	/**
	* Get the full name (path/file.ext) of a file/directory
	*
	* @param    array     $aFile          file/directory information array
	* @param    boolean   $endingSlash    add an ending slash for directories
	*/
	public function fullName( $aFile, $endingSlash = true )
	{
		$sBuffer = $this->getPath( $aFile );
		$sBuffer .= ($endingSlash) ? $this->fileName( $aFile ) : $this->directoryName( $aFile );
		return( $sBuffer );
	}
	/**
	* Get the filename
	*
	* @param    array     $aFile       file/directory information array
	*/
	public function fileName( $aFile )
	{
		$sBuffer = $this->directoryName( $aFile );
		if ( $this->getIsDirectory( $aFile ) )
			$sBuffer .= "/";

		return( $sBuffer );
	}
	/**
	* Get the directory name
	*
	* returns the same as FileName, but without a ending "/" for Directories.
	*
	* @param    array     $aFile       file/directory information array
	*/
	public function directoryName( $aFile )
	{
		$sBuffer = $this->getExtension( $aFile );
		if ( !empty( $sBuffer ) )
			$sBuffer = "." . $sBuffer;
		$sBuffer = $this->getFile( $aFile ) . $sBuffer;

		return( $sBuffer );
	}

	/**
	* 取得 treemenu 陣列
	*/
	public function getTreeMenuArr($arr){
		$pathArr = array();
		// 陣列 以 1 為起始, 因為 0 保留給 root
		for($i=0;$i<count($arr);$i++)
			$pathArr[$i+1] = $arr[$i];

		$ttt = array();

		foreach ($pathArr as $val){
			$aa = explode("/",$val);
			$the_key =  array_search($val,$pathArr);
			$parent = 0 ;
			if (count($aa)>1){
				$cc = strlen(end($aa))+1;
				$parent = array_search(substr($val,0,-$cc),$pathArr);
			}
			$ss['path'] = $val;
			$ss['floder_name'] = end($aa);
			$ss['parent']= $parent;
			$ttt[$the_key] = $ss;
		}
		$ttt2 = array();
		$i=1;
		foreach ($ttt as $val){
			$parent = $val['parent'];
			$ttt2[$parent][$i++] = $val;
		}
		return $ttt2;
	}
//[end]
}
